#pragma once
#include "udp_socket.hpp"
// C 式写法
// typedef void (*Handler)(const std::string& req, std::string* resp);
// C++ 11 式写法, 能够兼容函数指针, 仿函数, 和 lamda
#include <functional>

typedef std::function<void (const std::string&, std::string* resp)> Handler;

class UdpServer 
{
public:
 UdpServer() 
 {
 assert(sock_.Socket());
 }

 ~UdpServer() 
 {
 sock_.Close();
 }

// Start函数，用于启动UDP服务器。
// 参数包括：ip（服务器绑定的IP地址），port（服务器绑定的端口号），handler（处理请求的回调函数）
 bool Start(const std::string& ip, uint16_t port, Handler handler) 
 {
   // 1. 创建 socket
   // 2. 绑定端口号
   // 调用sock_对象的Bind方法，该方法会创建套接字并绑定。
   bool ret = sock_.Bind(ip, port);
   if (!ret) 
   {
     return false;
   }
   // 3. 进入事件循环
   for (;;) 
   {
   // 4. 尝试读取请求
   // 声明请求字符串req，远程IP地址remote_ip和远程端口remote_port。
   std::string req;
   std::string remote_ip;
   uint16_t remote_port = 0;
   // 调用sock_对象的RecvFrom方法，尝试接收来自客户端的数据。
   bool ret = sock_.RecvFrom(&req, &remote_ip, &remote_port);
   if (!ret) 
   {
    continue;
   }

   //调用传入的处理函数handler，根据接收到的请求req生成响应resp。
  // handler是一个回调函数，它的签名应该与这里的要求相匹配。
   std::string resp;
   handler(req, &resp);
   
   // 6. 将生成的响应通过套接字发送回客户端。
  // 使用sock_对象的SendTo方法，将响应发送到请求来源的IP地址和端口。
   sock_.SendTo(resp, remote_ip, remote_port);
   printf("[%s:%d] req: %s, resp: %s\n", remote_ip.c_str(), remote_port,req.c_str(), resp.c_str());
   }
   
   sock_.Close();
   return true;
 }
private:
 UdpSocket sock_;
};